﻿using BCCommon;
using BCCommon.OAEnums;
using BCData.MySql.BusinessFlowInstance;
using BCData.MySql.BusinessFlowStepInstance;
using BCData.OA.BusinessFlowPushRecord;
using BCData.OA.BusinessFlowRecord;
using BCData.Sim.Company.Company;
using BCDto.OA.BusinessFlowRecord;
using BCDto.OA.Notification.NotificationRecord;
using BCDto.Sim.Admin.Admin;
using BCEntity.MySql.BusinessFlowInstance;
using BCEntity.MySql.BusinessFlowStepInstance;
using BCEntity.OA.Common;
using BCService.OA.AuxiliaryRule;
using BCService.OA.BusinessFlowModel.BusinessFlowModel;
using BCService.OA.BusinessFlowModel.BusinessFlowStepModel;
using BCService.OA.Notification.NotificationRecord;
using BCService.OA.PageBusiness.PageBusinessMappingDepartment;
using BCService.Sim.Admin.StaffOrganizationMappingRecord;
using BCService.Sim.Company.Company;
using BCService.Sim.Company.Department;
using BCService.Utils;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace BCService.OA.BusinessFlow
{
    public class BusinessFlowService : IBusinessFlowService
    {
        private readonly IApplicationContextService applicationContextService;
        private readonly IBusinessFlowRecordData businessFlowRecordData;
        private readonly IBusinessFlowModelService businessFlowModelService;
        private readonly IBusinessFlowStepModelService businessFlowStepModelService;
        private readonly IPageBusinessMappingDepartmentService pageBusinessMappingDepartmentService;
        private readonly INotificationRecordService notificationRecordService;
        private readonly IBusinessFlowInstanceData businessFlowInstanceData;
        private readonly IBusinessFlowStepInstanceData businessFlowStepInstanceData;
        private readonly IBusinessFlowPushRecordData businessFlowPushRecordData;
        private readonly IAuxiliaryRuleService auxiliaryRuleService;
        private readonly IStaffOrganizationMappingRecordService staffOrganizationMappingRecordService;
        private readonly IDepartmentService departmentService;
        private readonly ICompanyService companyService;
        private readonly ICompanyData companyData;

        public BusinessFlowService(IApplicationContextService applicationContextService,
            IBusinessFlowRecordData businessFlowRecordData,
            IBusinessFlowModelService businessFlowModelService,
            IBusinessFlowStepModelService businessFlowStepModelService,
            IPageBusinessMappingDepartmentService pageBusinessMappingDepartmentService,
            INotificationRecordService notificationRecordService,
            IBusinessFlowInstanceData businessFlowInstanceData,
            IBusinessFlowStepInstanceData businessFlowStepInstanceData,
            IBusinessFlowPushRecordData businessFlowPushRecordData,
            IAuxiliaryRuleService auxiliaryRuleService,
            IStaffOrganizationMappingRecordService staffOrganizationMappingRecordService,
            IDepartmentService departmentService,
            ICompanyService companyService,
            ICompanyData companyData)
        {
            this.applicationContextService = applicationContextService;
            this.businessFlowRecordData = businessFlowRecordData;
            this.businessFlowModelService = businessFlowModelService;
            this.businessFlowStepModelService = businessFlowStepModelService;
            this.pageBusinessMappingDepartmentService = pageBusinessMappingDepartmentService;
            this.notificationRecordService = notificationRecordService;
            this.businessFlowInstanceData = businessFlowInstanceData;
            this.businessFlowStepInstanceData = businessFlowStepInstanceData;
            this.businessFlowPushRecordData = businessFlowPushRecordData;
            this.auxiliaryRuleService = auxiliaryRuleService;
            this.staffOrganizationMappingRecordService = staffOrganizationMappingRecordService;
            this.departmentService = departmentService;
            this.companyService = companyService;
            this.companyData = companyData;
        }

        #region 初始化业务流
        public void Init(long businessFlowRecordId)
        {
            var recordEntity = this.businessFlowRecordData.GetEntity(businessFlowRecordId).GetAwaiter().GetResult();
            if (recordEntity == null)
            {
                throw new ArgumentException("此记录不存在:" + businessFlowRecordId);
            }
            if (!this.businessFlowModelService.Exists(recordEntity.BusinessFlowModelCode))
            {
                throw new ArgumentException("此业务流不存在：" + businessFlowRecordId);
            }
            var businessFlowModelDto = this.businessFlowModelService.GetEntity(recordEntity.BusinessFlowModelCode);
            var businessFlowStepModelDtos = this.businessFlowStepModelService.GetList(businessFlowModelDto.BusinessFlowModelId);
            var instanceEntity = businessFlowModelDto.As<BusinessFlowInstanceEntity>();
            instanceEntity.BusinessFlowInstanceName = recordEntity.RecordTitle;
            instanceEntity.CurrentlyStep = 1;
            var instanceResult = this.businessFlowInstanceData.Add(instanceEntity).GetAwaiter().GetResult();
            if (instanceResult == null)
            {
                recordEntity.IsInitFailed = true;
                recordEntity.InitializedTime = DateTime.Now;
                recordEntity.FailedRemark = "添加实例失败";
                this.businessFlowRecordData.Update(recordEntity).GetAwaiter().GetResult();
            }
            var stepList = businessFlowStepModelDtos.As<List<BusinessFlowStepInstanceEntity>>();
            foreach (var item in stepList)
            {
                item.BusinessFlowInstanceId = instanceResult.BusinessFlowInstanceId;
                item.BusinessFlowInstanceName = instanceResult.BusinessFlowInstanceName;
                item.BusinessFlowStepInstanceName = instanceResult.BusinessFlowInstanceName + "，当前步骤：" + item.BusinessFlowStepModelName;
            }
            if (!this.businessFlowStepInstanceData.Add(stepList).GetAwaiter().GetResult())
            {
                recordEntity.IsInitFailed = true;
                recordEntity.InitializedTime = DateTime.Now;
                recordEntity.FailedRemark = "添加实例步骤失败";
                recordEntity.BusinessFlowInstanceId = instanceResult.BusinessFlowInstanceId;
                this.businessFlowRecordData.Update(recordEntity).GetAwaiter().GetResult();
                throw new ArgumentException("添加实例步骤失败" + businessFlowRecordId);
            }

            recordEntity.IsInitialized = true;
            recordEntity.InitializedTime = DateTime.Now;
            recordEntity.BusinessFlowInstanceId = instanceResult.BusinessFlowInstanceId;
            this.businessFlowRecordData.Update(recordEntity).GetAwaiter().GetResult();


        }

        #endregion

        #region 推进业务流
        public void PushBusinessFlow(BusinessFlowRecordDto businessFlowRecordDto, long businessFlowPushRecordId)
        {
            var pushRecordEntity = this.businessFlowPushRecordData.GetEntity(businessFlowPushRecordId).GetAwaiter().GetResult();
            var instanceEntity = this.businessFlowInstanceData.GetEntity(businessFlowRecordDto.BusinessFlowInstanceId).GetAwaiter().GetResult();
            instanceEntity.CurrentlyStep++;
            var instanceSteps = this.businessFlowStepInstanceData.GetList(businessFlowRecordDto.BusinessFlowInstanceId).GetAwaiter().GetResult();
            if (!instanceSteps.Any(p => p.Step == instanceEntity.CurrentlyStep))
            {
                string remark = string.Format("此业务步骤不存在,步骤:{0}, 业务流实例id:{1}", instanceEntity.CurrentlyStep, instanceEntity.BusinessFlowInstanceId);
                pushRecordEntity.PushFailRemark = remark;
                this.businessFlowPushRecordData.Update(pushRecordEntity).GetAwaiter().GetResult();
                throw new ArgumentException(remark);
            }
            var stepEntity = instanceSteps.Single(p => p.Step == instanceEntity.CurrentlyStep);

            var mappingList = this.pageBusinessMappingDepartmentService.GetList(instanceEntity.CompanyId, stepEntity.PageBusinessConfigId);

            List<NotificationRecordRequestDto> requestDtos = new List<NotificationRecordRequestDto>();
            List<ExecuteMethodUtilsEntity> methodList = new List<ExecuteMethodUtilsEntity>();
            foreach (var item in mappingList)
            {
                int companyId = item.CompanyId;
                int departmentId = item.DepartmentId;
                string companyName = item.CompanyName;
                string departmentName = item.DepartmentName;
                var oldDepartmentDto = this.departmentService.Get(departmentId);
                if (item.IsDynamicCompany)
                {
                    //#region 动态公司及部门(根据实际业务获取相关的归属公司，已抛弃配置中的公司及部门)
                    //switch (instanceEntity.BusinessFlowCategoryName)
                    //{
                    //    case "司机":
                    //        //TODO:根据司机Id和职位获取归属合伙人的归属公司的公司信息和职位对应的部门信息
                    //        {
                    //            long driverId = long.Parse(pushRecordEntity.ReferenceNo);
                    //            var driverDto = this.driverService.GetDriverInfo(driverId);
                    //            var userDto = this.userService.GetUserByUserId(driverDto.UserId);
                    //            var partnerDto = this.partnerService.Get(userDto.PartnerId.Value);
                    //            var companyDto = partnerDto.CompanyId.HasValue ? this.companyService.GetEntity(partnerDto.CompanyId.Value) : this.companyData.GetMainCompanyEntity().As<CompanyDto>();
                    //            companyId = companyDto.CompanyId;
                    //            companyName = companyDto.CompanyName;
                    //            var departments = this.departmentService.GetAll(companyId).GetAwaiter().GetResult();
                    //            if (!departments.Any(p => p.DepartmentFunction.Equals(oldDepartmentDto.DepartmentFunction)))
                    //            {
                    //                string remark = string.Format("此业务流归属公司缺少对应部门,步骤:{0}, 业务流实例id:{1},对应部门:{2}", instanceEntity.CurrentlyStep, instanceEntity.BusinessFlowInstanceId, oldDepartmentDto.DepartmentFunctionName);
                    //                pushRecordEntity.PushFailRemark = remark;
                    //                this.businessFlowPushRecordData.Update(pushRecordEntity).GetAwaiter().GetResult();
                    //                throw new ArgumentException(remark);
                    //            }
                    //            var newDepartmentDto = departments.First(p => p.DepartmentFunction.Equals(oldDepartmentDto.DepartmentFunction));
                    //            departmentId = newDepartmentDto.DepartmentId;
                    //            departmentName = newDepartmentDto.DepartmentName;
                    //        }
                    //        break;
                    //    case "车辆":
                    //        //TODO:根据车辆Id和职位获取归属合伙人的归属公司的公司信息和职位对应的部门信息
                    //        {
                    //            long vehicleId = long.Parse(pushRecordEntity.ReferenceNo);
                    //            var vehicleDto = this.vehicleService.Get(vehicleId);
                    //            var driverDto = this.driverService.GetDriverByDriverId(vehicleDto.DriverId);
                    //            var userDto = this.userService.GetUserByUserId(driverDto.UserId);
                    //            var partnerDto = this.partnerService.Get(userDto.PartnerId.Value);
                    //            var companyDto = partnerDto.CompanyId.HasValue ? this.companyService.GetEntity(partnerDto.CompanyId.Value) : this.companyData.GetMainCompanyEntity().As<CompanyDto>();
                    //            companyId = companyDto.CompanyId;
                    //            companyName = companyDto.CompanyName;
                    //            var departments = this.departmentService.GetAll(companyId).GetAwaiter().GetResult();
                    //            if (!departments.Any(p => p.DepartmentFunction.Equals(oldDepartmentDto.DepartmentFunction)))
                    //            {
                    //                string remark = string.Format("此业务流归属公司缺少对应部门,步骤:{0}, 业务流实例id:{1},对应部门:{2}", instanceEntity.CurrentlyStep, instanceEntity.BusinessFlowInstanceId, oldDepartmentDto.DepartmentFunctionName);
                    //                pushRecordEntity.PushFailRemark = remark;
                    //                this.businessFlowPushRecordData.Update(pushRecordEntity).GetAwaiter().GetResult();
                    //                throw new ArgumentException(remark);
                    //            }
                    //            var newDepartmentDto = departments.First(p => p.DepartmentFunction.Equals(oldDepartmentDto.DepartmentFunction));
                    //            departmentId = newDepartmentDto.DepartmentId;
                    //            departmentName = newDepartmentDto.DepartmentName;
                    //        }
                    //        break;
                    //    case "合伙人":
                    //        //TODO:根据合伙人Id和职位获取归属公司的公司信息和职位对应的部门信息
                    //        {
                    //            long partnerId = long.Parse(pushRecordEntity.ReferenceNo);
                    //            var partnerDto = this.partnerService.Get(partnerId);
                    //            var companyDto = partnerDto.CompanyId.HasValue ? this.companyService.GetEntity(partnerDto.CompanyId.Value) : this.companyData.GetMainCompanyEntity().As<CompanyDto>();
                    //            companyId = companyDto.CompanyId;
                    //            companyName = companyDto.CompanyName;
                    //            var departments = this.departmentService.GetAll(companyId).GetAwaiter().GetResult();
                    //            if (!departments.Any(p => p.DepartmentFunction.Equals(oldDepartmentDto.DepartmentFunction)))
                    //            {
                    //                string remark = string.Format("此业务流归属公司缺少对应部门,步骤:{0}, 业务流实例id:{1},对应部门:{2}", instanceEntity.CurrentlyStep, instanceEntity.BusinessFlowInstanceId, oldDepartmentDto.DepartmentFunctionName);
                    //                pushRecordEntity.PushFailRemark = remark;
                    //                this.businessFlowPushRecordData.Update(pushRecordEntity).GetAwaiter().GetResult();
                    //                throw new ArgumentException(remark);
                    //            }
                    //            var newDepartmentDto = departments.First(p => p.DepartmentFunction.Equals(oldDepartmentDto.DepartmentFunction));
                    //            departmentId = newDepartmentDto.DepartmentId;
                    //            departmentName = newDepartmentDto.DepartmentName;
                    //        }
                    //        break;
                    //    case "用户":
                    //        //TODO:根据用户Id和职位获取归属合伙人的归属公司的公司信息和职位对应的部门信息
                    //        {
                    //            long userId = long.Parse(pushRecordEntity.ReferenceNo);
                    //            var userDto = this.userService.GetUserByUserId(userId);
                    //            var partnerDto = this.partnerService.Get(userDto.PartnerId.Value);
                    //            var companyDto = partnerDto.CompanyId.HasValue ? this.companyService.GetEntity(partnerDto.CompanyId.Value) : this.companyData.GetMainCompanyEntity().As<CompanyDto>();
                    //            companyId = companyDto.CompanyId;
                    //            companyName = companyDto.CompanyName;
                    //            var departments = this.departmentService.GetAll(companyId).GetAwaiter().GetResult();
                    //            if (!departments.Any(p => p.DepartmentFunction.Equals(oldDepartmentDto.DepartmentFunction)))
                    //            {
                    //                string remark = string.Format("此业务流归属公司缺少对应部门,步骤:{0}, 业务流实例id:{1},对应部门:{2}", instanceEntity.CurrentlyStep, instanceEntity.BusinessFlowInstanceId, oldDepartmentDto.DepartmentFunctionName);
                    //                pushRecordEntity.PushFailRemark = remark;
                    //                this.businessFlowPushRecordData.Update(pushRecordEntity).GetAwaiter().GetResult();
                    //                throw new ArgumentException(remark);
                    //            }
                    //            var newDepartmentDto = departments.First(p => p.DepartmentFunction.Equals(oldDepartmentDto.DepartmentFunction));
                    //            departmentId = newDepartmentDto.DepartmentId;
                    //            departmentName = newDepartmentDto.DepartmentName;
                    //        }
                    //        break;
                    //    default:
                    //        break;
                    //}
                    //#endregion

                    NotificationRecordRequestDto requestDto = new NotificationRecordRequestDto()
                    {
                        Title = stepEntity.BusinessFlowStepModelName,
                        Content = stepEntity.BusinessFlowStepInstanceName,
                        RelatedType = OARelatedType.Business,
                        NotificationRange = item.IsAllJobTitle ? OANotificationRangeType.Department : OANotificationRangeType.JobTitle,
                        PageBusinessConfigId = item.PageBusinessConfigId,
                        PageBusinessName = item.PageBusinessName,
                        PageBusinessCode = item.PageBusinessCode,
                        RelatedBusinessCategoryId = instanceEntity.BusinessFlowCategoryId,
                        RelatedBusinessCategoryName = instanceEntity.BusinessFlowCategoryName,
                        RelatedBusinessRecordId = businessFlowRecordDto.BusinessFlowRecordId,
                        RelatedReferenceNo = pushRecordEntity.RelatedReferenceNo,
                        RelatedBusinessTaskLevel = instanceEntity.BusinessTaskLevel,
                        NotificationCategoryId = item.NotificationCategoryId,
                        NotificationCategoryCode = item.NotificationCategoryCode,
                        NotificationCategoryName = item.NotificationCategoryName,
                        CompanyId = companyId,
                        CompanyName = companyName,
                        DepartmentId = departmentId,
                        DepartmentName = departmentName,
                        AllowJobTitle = item.AllowJobTitle,
                        AllowJobTitleStr = item.AllowJobTitleStr,
                        StartTime = DateTime.Now,
                        EndTime = DateTime.Now.AddHours(item.PredefinedTimeoutHour),
                        StartYear = DateTime.Now.Year,
                        StartMonth = DateTime.Now.Month
                    };

                    if (requestDto.NotificationRange == OANotificationRangeType.Staff)
                    {
                        //待补充
                        //ReceiverId 
                    }

                    if (item.IsEnabledAuxiliaryRule)
                    {
                        var staffList = this.staffOrganizationMappingRecordService.GetDepartmentStaffList(departmentId);

                        var ruleDto = this.auxiliaryRuleService.GetEntityByPageBusinessConfigId(item.PageBusinessConfigId);
                        if (ruleDto != null)
                        {
                            var parameters = new List<object>();
                            if (!string.IsNullOrWhiteSpace(ruleDto.ServiceMethodParameters))
                            {
                                foreach (string p in ruleDto.ServiceMethodParameters.Split(','))
                                {
                                    string[] v = p.Split('=');
                                    if (v[0] == "businessFlowInstanceId")
                                    {
                                        parameters.Add(businessFlowRecordDto.BusinessFlowInstanceId);
                                    }
                                    else if (v[0] == "staffList")
                                    {
                                        parameters.Add(staffList);
                                    }
                                    else
                                    {
                                        parameters.Add(v[1]);
                                    }
                                }
                            }

                            object methodResult = applicationContextService.RequestServices.ExecuteMethod(ruleDto.ServiceName, ruleDto.ServiceMethodName, parameters);
                            string json = JsonConvert.SerializeObject(methodResult);
                            List<AdminDto> adminDtos = JsonConvert.DeserializeObject<List<AdminDto>>(json);
                            foreach (var admin in adminDtos)
                            {
                                requestDto.NotificationRange = OANotificationRangeType.Staff;
                                requestDto.ReceiverId = admin.AdminId;
                                requestDto.ReceiverRole = OAPeopleRoleType.Admin;
                                requestDto.ReceiverName = admin.FullName;
                                requestDtos.Add(requestDto);
                            }
                        }
                    }
                    else
                    {
                        requestDtos.Add(requestDto);
                    }
                }
            }

            var notificationRecordDto = this.notificationRecordService.Add(requestDtos);
            if (notificationRecordDto)
            {
                pushRecordEntity.IsPushed = true;
                pushRecordEntity.PushCount++;
                pushRecordEntity.PushTime = DateTime.Now;
            }
            else
            {
                pushRecordEntity.IsPushFailed = true;
                pushRecordEntity.PushCount++;
                pushRecordEntity.PushTime = DateTime.Now;
                pushRecordEntity.FailCount++;
            }

            var result = this.businessFlowPushRecordData.Update(pushRecordEntity).GetAwaiter().GetResult();
            if (result == null)
            {
                string remark = string.Format("更新业务推进记录失败,步骤:{0}, 业务流实例id:{1},推进记录Id:{2}", instanceEntity.CurrentlyStep, instanceEntity.BusinessFlowInstanceId, pushRecordEntity.BusinessFlowPushRecordId);
                pushRecordEntity.PushFailRemark = remark;
                this.businessFlowPushRecordData.Update(pushRecordEntity).GetAwaiter().GetResult();
                throw new ArgumentException(remark);
            }

            var instanceResult = this.businessFlowInstanceData.Update(instanceEntity).GetAwaiter().GetResult();
            if (instanceResult == null)
            {
                string remark = string.Format("更新实例当前步骤失败,步骤:{0}, 业务流实例id:{1}", instanceEntity.CurrentlyStep, instanceEntity.BusinessFlowInstanceId);
                pushRecordEntity.PushFailRemark = remark;
                this.businessFlowPushRecordData.Update(pushRecordEntity).GetAwaiter().GetResult();
                throw new ArgumentException(remark);
            }
        }
        #endregion
    }
}
